/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package cs5631threadinglab;

import java.util.Random;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *
 * @author brady
 */
public class Agent extends Thread {

    Environment environment;
    Particle particle;
    Random r;
    int cRow, cCol;
    boolean allowRun;
    boolean pause = false;
    double pickup, drop;
    boolean halted = false;


    /**
     * Constructor
     * @param e environment this agent is acting on
     * @param initRow row of the cell to start running in
     * @param initCol column of the cell to start running in
     * @param pickupProb probability of picking up a particle
     * @param dropProb probablilty of dropping a particle
     */
    public Agent(Environment e, int initRow, int initCol, double pickupProb, double dropProb) {
        cRow = initRow;
        cCol = initCol;
        environment = e;
        particle = null;
        r = new Random();
        pickup = pickupProb;
        drop = dropProb;
    }

    @Override
    /**
     * runs this thread
     */
    public void run() {
        allowRun = true;
        while (allowRun) {
            if(pause)
            {
                DropParticle(1.1);
                this.halted = true;
                synchronized (this) {
                    try {
                        wait();
                    } catch (InterruptedException ex) {
                        Logger.getLogger(Agent.class.getName()).log(Level.SEVERE, null, ex);
                    }
                    pause = false;
                    this.halted = false;
                }
            }
            Move();
            if (PickUpParticle()) {
                continue;
            } else {
                DropParticle(drop);
            }
        }
        //here allowRun has been set to false, stop the thread
        DropParticle(1.1);
    }


    /**
     * asks the environment for the particle at the agent's current cell if any
     * @return true if it obtained a particle, false if it failed to get a particle
     */
    boolean PickUpParticle() {
        double rgen = r.nextDouble();
        if (particle == null && rgen < pickup) {
                particle = environment.GetParticleFromCell(cRow, cCol);
                if (particle != null) {
                    return true;
                }
                else return false;
        }
        else {
            return false;
        }
    }

    /**
     * drops a particle onto the current cell in the environment
     * @param prob probability of dropping the particle
     * @return true if it successfully dropped, else false
     */
    public boolean DropParticle(double prob) {
        double rgen = r.nextDouble();
        if (particle != null && rgen < prob) {
            boolean success = environment.GiveParticleToCell(particle, cRow, cCol);
            if(success)
                particle = null;
            return success;
        } else {
            return false;
        }
    }

    /**
     * Moves this agent to a different cell in the environment
     */
    public void Move() {
        Cell newCell = null;
        while (newCell == null) {
            int dir = r.nextInt(4);
            if (dir == 0) {
                newCell = environment.GetCell(cRow - 1, cCol);
            }
            if (dir == 1) {
                newCell = environment.GetCell(cRow, cCol + 1);
            }
            if (dir == 2) {
                newCell = environment.GetCell(cRow + 1, cCol);
            }
            if (dir == 3) {
                newCell = environment.GetCell(cRow, cCol - 1);
            }
        }
        cRow = newCell.row;
        cCol = newCell.col;
    }

    /**
     * pauses the execution of this agent
     */
    synchronized void pauseAgent()
    {
        pause = true;
    }

    /**
     * Resumes this agent after pausing
     */
    synchronized void resumeAgent()
    {
        this.notify();
    }

}//end class Agent

